﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Diagnostics;

namespace Arnej.FriendFeed.Api
{
    internal struct FriendFeedUrls
    {
        internal static string PublicFeed =
            "http://www.friendfeed.com/api/feed/public?format=xml";
        internal static string UserFeed =
            "http://www.friendfeed.com/api/feed/user/{0}?format=xml";
        internal static string UsersFeed =
            "http://www.friendfeed.com/api/feed/user?format=xml";
        internal static string CommentsFeed =
            "http://www.friendfeed.com/api/feed/user/{0}/comments?format=xml";
        internal static string LikesFeed =
            "http://www.friendfeed.com/api/feed/user/{0}/likes?format=xml";
        internal static string DiscussionsFeed =
            "http://www.friendfeed.com/api/feed/user/{0}/discussion?format=xml";
        internal static string RoomFeed =
            "http://www.friendfeed.com/api/feed/room/{0}?format=xml";
        internal static string FriendFeed =
            "http://www.friendfeed.com/api/feed/home?format=xml";
        internal static string SearchFeed =
            "http://www.friendfeed.com/api/feed/search?format=xml";
        internal static string Entry =
            "http://www.friendfeed.com/api/share?format=xml";
        internal static string CommentAdd =
            "http://www.friendfeed.com/api/comment?format=xml";
        internal static string CommentEdit =
            "http://www.friendfeed.com/api/comment?format=xml";
        internal static string CommentDelete =
            "http://www.friendfeed.com/api/comment/delete?format=xml";
        internal static string LikeAdd =
            "http://www.friendfeed.com/api/like?format=xml";
        internal static string LikeEdit =
            "http://www.friendfeed.com/api/like?format=xml";
        internal static string LikeDelete =
            "http://www.friendfeed.com/api/like/delete?format=xml";
        internal static string Profile =
            "http://www.friendfeed.com/api/user/{0}/profile?format=xml";
        internal static string Profiles =
            "http://www.friendfeed.com/api/profiles?format=xml";
    }

    public class FriendFeedClient
    {
        private CredentialCache credentialCache = null;

        private int defaultStartEntry = 0;

        public int DefaultStartEntry
        {
            get { return defaultStartEntry; }
            set { defaultStartEntry = value; }
        }

        private int defaultNumberOfEntries = 30;

        public int DefaultNumberOfEntries
        {
            get { return defaultNumberOfEntries; }
            set { defaultNumberOfEntries = value; }
        }

        public FriendFeedClient(string nickname, string remoteKey)
        {
            credentialCache = new CredentialCache();
            credentialCache.Add(
                new Uri("http://friendfeed.com/api/"),
                "Basic",
                new NetworkCredential(
                    nickname, remoteKey));
        }

        public Feed GetPublicFeed()
        {
            return GetPublicFeed(null, defaultStartEntry, defaultNumberOfEntries);
        }

        public Feed GetPublicFeed(int startEntry, int numberOfEntries)
        {
            return GetPublicFeed(null, startEntry, numberOfEntries);
        }

        public Feed GetPublicFeed(string serviceId)
        {
            return GetPublicFeed(
                new Service() { Id = serviceId }, defaultStartEntry, defaultNumberOfEntries);
        }

        public Feed GetPublicFeed(Service service)
        {
            return GetPublicFeed(service, defaultStartEntry, defaultNumberOfEntries);
        }

        public Feed GetPublicFeed(Service service, int startEntry, int numberOfEntries)
        {
            StringBuilder sb = new StringBuilder(
                FriendFeedUrls.PublicFeed);
            if (service != null)
            {
                sb.Append("&service=");
                sb.Append(service.Id);  
            }
            sb.Append("&start=");
            sb.Append(startEntry);
            sb.Append("&num=");
            sb.Append(numberOfEntries);
            Feed feed = MakeRequest<Feed>(sb.ToString());
            return feed;
        }

        public Feed GetUserFeed()
        {
            return GetUserFeed(defaultStartEntry, defaultNumberOfEntries);
        }

        public Feed GetUserFeed(int startEntry, int numberOfEntries)
        {
            return GetUserFeed(startEntry, numberOfEntries);
        }

        public Feed GetUserFeed(string serviceId)
        {
            return GetFriendFeed(
                new Service() { Id = serviceId }, defaultStartEntry, defaultNumberOfEntries);
        }

        public Feed GetUserFeed(Service service)
        {
            return GetUserFeed(service, defaultStartEntry, defaultNumberOfEntries);
        }

        public Feed GetUserFeed(string serviceId, int startEntry, int numberOfEntries)
        {
            return GetUserFeed(new Service() { Id = serviceId }, startEntry, numberOfEntries);
        }

        public Feed GetUserFeed(Service service, int startEntry, int numberOfEntries)
        {
            StringBuilder sb = new StringBuilder(
                FriendFeedUrls.UserFeed);
            if (service != null)
            {
                sb.Append("&service=");
                sb.Append(service.Id);
            }
            sb.Append("&start=");
            sb.Append(startEntry);
            sb.Append("&num=");
            sb.Append(numberOfEntries);
            Feed feed = MakeRequest<Feed>(sb.ToString());
            return feed;
        }

        public Feed GetMultipleUsersFeed(string nickname, params string[] nicknames)
        {
            List<User> users = new List<User>();
            users.Add(new User() { Nickname = nickname });
            foreach (string name in nicknames)
            {
                users.Add(new User() { Nickname = name });
            }

            return GetMultipleUsersFeed(
                users, null, defaultStartEntry, defaultNumberOfEntries);
        }

        public Feed GetMultipleUsersFeed(List<User> users)
        {
            return GetMultipleUsersFeed(
                users, null, defaultStartEntry, defaultNumberOfEntries);
        }

        public Feed GetMultipleUsersFeed(List<User> users, int startEntry, int numberOfEntries)
        {
            return GetMultipleUsersFeed(users, null, startEntry, numberOfEntries);
        }

        public Feed GetMultipleUsersFeed(List<User> users, Service service)
        {
            return GetMultipleUsersFeed(
                users, service, defaultStartEntry, defaultNumberOfEntries);
        }

        public Feed GetMultipleUsersFeed(
            List<User> users, Service service, int startEntry, int numberOfEntries)
        {
            StringBuilder sb = new StringBuilder(
                FriendFeedUrls.UsersFeed);

            //TODO:kann man das nicht mit LINQ viel eleganter lösen?
            if (users != null)
            {
                sb.Append("&nickname=");
                for (int i = 0; i < users.Count; i++)
                {
                    sb.Append(users[i].Nickname);
                    if (i < users.Count - 1)
                    {
                        sb.Append(",");
                    }
                }
            }

            if (service != null)
            {
                sb.Append("&service=");
                sb.Append(service.Id);
            }
            sb.Append("&start=");
            sb.Append(startEntry);
            sb.Append("&num=");
            sb.Append(numberOfEntries);
            Feed feed = MakeRequest<Feed>(sb.ToString());
            return feed;
        }

        public Feed GetUserComments(string nickName)
        {
            return GetUserComments(
                new User() { Nickname = nickName }, null, defaultStartEntry, defaultNumberOfEntries);
        }

        public Feed GetUserComments(User user)
        {
            return GetUserComments(user, null, defaultStartEntry, defaultNumberOfEntries);
        }

        public Feed GetUserComments(User user, int startEntry, int numberOfEntries)
        {
            return GetUserComments(user, null, startEntry, numberOfEntries);
        }

        public Feed GetUserComments(User user, Service service)
        {
            return GetUserComments(user, service, 0, 30);
        }

        public Feed GetUserComments(User user, Service service, int startEntry, int numberOfEntries)
        {
            string url =
                string.Format(FriendFeedUrls.CommentsFeed, user.Nickname);

            StringBuilder sb = new StringBuilder(url);

            //TODO: Auch hier wieder: LINQ?
            if (service != null)
            {
                sb.Append("&service=");
                sb.Append(service.Id);
            }
            sb.Append("&start=");
            sb.Append(startEntry);
            sb.Append("&num=");
            sb.Append(numberOfEntries);
            Feed feed = MakeRequest<Feed>(sb.ToString());
            return feed;
        }

        public Feed GetUserLikes(string nickname)
        {
            return GetUserLikes(
                new User() { Nickname = nickname }, null, defaultStartEntry, defaultNumberOfEntries);
        }

        public Feed GetUserLikes(User user)
        {
            return new Feed();
        }

        public Feed GetUserLikes(User user, int startEntry, int numberOfEntries)
        {
            return new Feed();
        }

        public Feed GetUserLikes(User user, Service service)
        {
            return new Feed();
        }

        public Feed GetUserLikes(User user, Service service, int startEntry, int numberOfEntries)
        {
            return new Feed();
        }

        public Feed GetUserDiscussion(string nickname)
        {
            return GetUserDiscussion(
                new User() { Nickname = nickname }, null, defaultStartEntry, defaultNumberOfEntries);
        }

        public Feed GetUserDiscussion(User user)
        {
            return new Feed();
        }

        public Feed GetUserDiscussion(User user, int startEntry, int numberOfEntries)
        {
            return new Feed();
        }

        public Feed GetUserDiscussion(string nickname, string serviceId)
        {
            return GetUserDiscussion(
                new User() { Nickname = nickname },
                new Service() { Id = serviceId }, defaultStartEntry, defaultNumberOfEntries);
        }

        public Feed GetUserDiscussion(User user, Service service)
        {
            return new Feed();
        }

        public Feed GetUserDiscussion(string nickname, string serviceId, int startEntry, int numberOfEntries)
        {
            return GetUserDiscussion(
                new User() { Nickname = nickname },
                new Service() { Id = serviceId }, startEntry, numberOfEntries);
        }

        public Feed GetUserDiscussion(User user, Service service, int startEntry, int numberOfEntries)
        {
            return new Feed();
        }

        public Feed GetFriendFeed()
        {
            return GetFriendFeed(null, defaultStartEntry, defaultNumberOfEntries);
        }

        public Feed GetFriendFeed(int startEntry, int numberOfEntries)
        {
            return GetFriendFeed(null, startEntry, numberOfEntries);
        }

        public Feed GetFriendFeed(string serviceId)
        {
            return GetFriendFeed(
                new Service() { Id = serviceId }, defaultStartEntry, defaultNumberOfEntries);
        }

        public Feed GetFriendFeed(Service service)
        {
            return GetFriendFeed(service, defaultStartEntry, defaultNumberOfEntries);
        }

        public Feed GetFriendFeed(Service service, int startEntry, int numberOfEntries)
        {
            return new Feed();
        }

        public Feed Search(string query)
        {
            return Search(null, null, query, defaultStartEntry, defaultNumberOfEntries);
        }

        public Feed Search(string query, int startEntry, int numberOfEntries)
        {
            return Search(null, null, query, startEntry, numberOfEntries);
        }

        public Feed Search(User user, string query)
        {
            return new Feed();
        }

        public Feed Search(User user, string query, int start, int num)
        {
            return new Feed();
        }

        public Feed Search(User user, Service service, string query)
        {
            return new Feed();
        }

        public Feed Search(User user, Service service, string query, int start, int num)
        {
            return new Feed();
        }

        public Feed Search(Service service, string query)
        {
            return new Feed();
        }

        public Feed Search(Service service, string query, int start, int num)
        {
            return new Feed();
        }

        public Entry AddEntry(Entry entry)
        {
            return new Entry();
        }

        public Entry AddComment(Entry entry, Comment comment)
        {
            return new Entry();
        }

        public Entry EditComment(Entry entry, Comment comment)
        {
            return new Entry();
        }

        public Entry DeleteComment(Entry entry, Comment comment)
        {
            return new Entry();
        }

        public Entry AddLike(Entry entry)
        {
            return new Entry();
        }

        public Entry DeleteLike(Entry entry)
        {
            return new Entry();
        }

        public User GetProfile(User user)
        {
            return new User();
        }

        public List<User> GetProfiles(List<User> users)
        {
            return new List<User>();
        }

        private T MakeRequest<T>(string url)
        {
            HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
            request.Credentials = credentialCache;
            request.UserAgent = "http://www.friendfeed.com/arnej doing his own client";
            using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
            {
                T returnValue = Util.Deserialize<T>(response.GetResponseStream());
                response.Close();
                return returnValue;
            }
        }

    }

    public class FriedFeedClientException : ApplicationException
    {
        public override string Message
        {
            get
            {
                return base.Message;
            }
        }
    }
}